"""
市场数据广播服务
==================

后台任务服务，定期获取市场数据并通过WebSocket广播给订阅的客户端

Features:
- 后台异步任务
- 定期获取市场数据
- 自动广播到订阅客户端
- 可配置的更新间隔
- 错误处理和重试
"""

import asyncio
import logging
from datetime import datetime, timedelta
from typing import Dict, List, Optional, Set
from dataclasses import dataclass, field

from .service import websocket_service, WebSocketService
from ..core.market_data_service_v2 import MarketDataServiceV2

logger = logging.getLogger(__name__)


@dataclass
class BroadcastConfig:
    """广播配置"""
    # 更新间隔（秒）
    update_interval: int = 5
    # 是否启用
    enabled: bool = True
    # 批量处理大小
    batch_size: int = 10
    # 错误重试次数
    max_retries: int = 3
    # 重试延迟（秒）
    retry_delay: int = 1


class MarketDataBroadcaster:
    """
    市场数据广播服务
    
    负责定期获取市场数据并推送到订阅的WebSocket客户端
    """
    
    def __init__(
        self,
        market_data_service: MarketDataServiceV2,
        websocket_service: WebSocketService,
        config: Optional[BroadcastConfig] = None
    ):
        """
        初始化广播服务
        
        Args:
            market_data_service: 市场数据服务实例
            websocket_service: WebSocket服务实例
            config: 广播配置
        """
        self.market_data_service = market_data_service
        self.websocket_service = websocket_service
        self.config = config or BroadcastConfig()
        
        self._running = False
        self._task: Optional[asyncio.Task] = None
        self._last_broadcast_time: Dict[str, datetime] = {}
        
        logger.info(f"MarketDataBroadcaster initialized with config: {self.config}")
    
    async def start(self):
        """启动广播服务"""
        if self._running:
            logger.warning("MarketDataBroadcaster is already running")
            return
        
        if not self.config.enabled:
            logger.info("MarketDataBroadcaster is disabled in config")
            return
        
        self._running = True
        self._task = asyncio.create_task(self._broadcast_loop())
        logger.info("MarketDataBroadcaster started")
    
    async def stop(self):
        """停止广播服务"""
        if not self._running:
            return
        
        self._running = False
        
        if self._task:
            self._task.cancel()
            try:
                await self._task
            except asyncio.CancelledError:
                pass
        
        logger.info("MarketDataBroadcaster stopped")
    
    async def _broadcast_loop(self):
        """广播主循环"""
        logger.info("Market data broadcast loop started")
        
        while self._running:
            try:
                # 获取所有需要更新的订阅标的
                symbols = self._get_subscribed_symbols()
                
                if symbols:
                    logger.debug(f"Broadcasting data for {len(symbols)} symbols: {symbols}")
                    await self._broadcast_for_symbols(symbols)
                else:
                    logger.debug("No subscriptions found, skipping broadcast")
                
                # 等待下一次更新
                await asyncio.sleep(self.config.update_interval)
                
            except asyncio.CancelledError:
                logger.info("Broadcast loop cancelled")
                break
            except Exception as e:
                logger.error(f"Error in broadcast loop: {e}", exc_info=True)
                # 发生错误时等待一段时间再继续
                await asyncio.sleep(self.config.retry_delay)
    
    def _get_subscribed_symbols(self) -> List[str]:
        """
        获取所有订阅的标的代码
        
        Returns:
            List[str]: 标的代码列表
        """
        try:
            # 从WebSocket服务获取所有订阅
            subscriptions = self.websocket_service.get_all_subscriptions()
            return list(subscriptions)
        except Exception as e:
            logger.error(f"Failed to get subscribed symbols: {e}")
            return []
    
    async def _broadcast_for_symbols(self, symbols: List[str]):
        """
        为指定标的广播数据
        
        Args:
            symbols: 标的代码列表
        """
        # 分批处理
        for i in range(0, len(symbols), self.config.batch_size):
            batch = symbols[i:i + self.config.batch_size]
            
            # 并发获取数据
            tasks = [self._fetch_and_broadcast(symbol) for symbol in batch]
            results = await asyncio.gather(*tasks, return_exceptions=True)
            
            # 记录错误
            for symbol, result in zip(batch, results):
                if isinstance(result, Exception):
                    logger.error(f"Failed to broadcast data for {symbol}: {result}")
    
    async def _fetch_and_broadcast(self, symbol: str) -> bool:
        """
        获取并广播单个标的的数据
        
        Args:
            symbol: 标的代码
            
        Returns:
            bool: 是否成功
        """
        retries = 0
        last_error = None
        
        while retries < self.config.max_retries:
            try:
                # 获取实时数据
                data = await self._fetch_realtime_data(symbol)
                
                if data:
                    # 广播数据
                    count = await self.websocket_service.broadcast_data(symbol, data)
                    
                    # 更新最后广播时间
                    self._last_broadcast_time[symbol] = datetime.now()
                    
                    logger.debug(f"Successfully broadcasted data for {symbol} to {count} clients")
                    return True
                else:
                    logger.warning(f"No data available for {symbol}")
                    return False
                    
            except Exception as e:
                last_error = e
                retries += 1
                
                if retries < self.config.max_retries:
                    logger.warning(
                        f"Failed to fetch/broadcast data for {symbol} "
                        f"(attempt {retries}/{self.config.max_retries}): {e}"
                    )
                    await asyncio.sleep(self.config.retry_delay)
                else:
                    logger.error(
                        f"Failed to fetch/broadcast data for {symbol} "
                        f"after {self.config.max_retries} attempts: {e}"
                    )
        
        return False
    
    async def _fetch_realtime_data(self, symbol: str) -> Optional[Dict]:
        """
        获取实时数据
        
        Args:
            symbol: 标的代码
            
        Returns:
            Dict: 市场数据，如果获取失败则返回None
        """
        try:
            # 尝试获取最近的K线数据作为"实时"数据
            end_date = datetime.now()
            start_date = end_date - timedelta(days=7)  # 获取最近7天数据
            
            bars = await self.market_data_service.get_historical_bars(
                symbol=symbol,
                start_time=start_date,
                end_time=end_date,
                frequency="1d",  # 日线数据
                source="tushare"  # 默认使用tushare
            )
            
            if not bars:
                return None
            
            # 获取最新的一条数据
            latest_bar = bars[-1]
            
            # 计算涨跌
            prev_close = bars[-2].close if len(bars) >= 2 else latest_bar.open
            change = float(latest_bar.close) - float(prev_close)
            change_percent = (change / float(prev_close)) * 100 if prev_close else 0
            
            # 构建数据
            data = {
                "symbol": symbol,
                "timestamp": latest_bar.timestamp.isoformat(),
                "open": float(latest_bar.open),
                "high": float(latest_bar.high),
                "low": float(latest_bar.low),
                "close": float(latest_bar.close),
                "volume": float(latest_bar.volume) if latest_bar.volume else 0,
                "amount": float(latest_bar.amount) if latest_bar.amount else 0,
                "change": round(change, 2),
                "change_percent": round(change_percent, 2),
                "prev_close": float(prev_close)
            }
            
            return data
            
        except Exception as e:
            logger.error(f"Failed to fetch realtime data for {symbol}: {e}", exc_info=True)
            return None
    
    def get_stats(self) -> Dict:
        """
        获取广播统计信息
        
        Returns:
            Dict: 统计信息
        """
        return {
            "running": self._running,
            "enabled": self.config.enabled,
            "update_interval": self.config.update_interval,
            "last_broadcast_count": len(self._last_broadcast_time),
            "last_broadcast_symbols": list(self._last_broadcast_time.keys()),
            "subscribed_symbols": self._get_subscribed_symbols()
        }


# 全局广播服务实例（将在应用启动时初始化）
_broadcaster: Optional[MarketDataBroadcaster] = None


def get_broadcaster() -> Optional[MarketDataBroadcaster]:
    """获取广播服务实例"""
    return _broadcaster


def set_broadcaster(broadcaster: MarketDataBroadcaster):
    """设置广播服务实例"""
    global _broadcaster
    _broadcaster = broadcaster


async def initialize_broadcaster(
    market_data_service: MarketDataServiceV2,
    config: Optional[BroadcastConfig] = None
) -> MarketDataBroadcaster:
    """
    初始化并启动广播服务
    
    Args:
        market_data_service: 市场数据服务实例
        config: 广播配置
        
    Returns:
        MarketDataBroadcaster: 广播服务实例
    """
    global _broadcaster
    
    if _broadcaster:
        logger.warning("Broadcaster already initialized, stopping old instance")
        await _broadcaster.stop()
    
    # 创建新实例
    _broadcaster = MarketDataBroadcaster(
        market_data_service=market_data_service,
        websocket_service=websocket_service,
        config=config
    )
    
    # 启动服务
    await _broadcaster.start()
    
    return _broadcaster


async def cleanup_broadcaster():
    """清理广播服务"""
    global _broadcaster
    
    if _broadcaster:
        await _broadcaster.stop()
        _broadcaster = None

